BBEdit was a relatively unknown application that was used primarily by serious programmers working in CodeWarrior and other C++ compilers until the World Wide Web arrived on the scene. With HTML files being merely glorified text files, a great many people suddenly needed a powerful and complete text-based editor on the Mac. BBEdit was there waiting all along.
In its latest incarnations, BBEdit includes a complete suite of text-based HTML tools. BBEdit's extensive AppleScript support extends to these new HTML tools, making BBEdit a powerhouse for scripted HTML creation and modification.
Fig. w1.1 Entering some sample text into
a new file in BBEdit
For all of the following scripts that use BBEdit, you will need at least a couple simple text files. You can find some old SimpleText-based Read Me files on your hard drive, or you can follow the steps below to quickly create a couple of files. In either case, place your text files in folder named Text Files in a readily accessible place like the Desktop.
All the scripts that follow were designed and tested for BBEdit 4.5. BBEdit is published by Bare Bones Software, who can be reached at http://www.barebones.com/.
To get ready for the following AppleScripts for BBEdit:
Fig. w1.1 Entering some sample text into a
new file in BBEdit
Fig. w1.2 Entering more sample text into a
second new file in BBEdit.
One of BBEdit's most powerful features is its ability to search for patterns of text and then replace them with new text. This pattern searching feature is derived from abilities found in UNIX systems and is known by the UNIX term "grep." The power of this feature is simply too great to describe in a few words, but perhaps an example will serve to illustrate the potential of grep searches.
Code w1.1 finds every instance in a file of the word "the" followed by a space and another word and replaces it with the words "the crazy." We won't need to manually open any file in BBEdit since our script will handle this for us. This script can be run from the Script Editor.
A quick guide to grep patterns
. |
matches any character. |
# |
matches any digit. |
^ |
matches the beginning of a line. |
$ |
matches the end of a line. |
[abc] |
matches any character a, b, or c. |
[^abc] |
matches any character except a, b, or c. |
[a-e] |
matches any character from a to e. |
\t |
matches a tab. |
\r |
matches a return. |
A* |
matches zero or more A's. |
A+ |
matches one or more A's. |
A? |
matches zero or one A. |
(A) |
creates a group match that can be referred to in the replace string by \n, where n refers to the nth instance of (), i.e. \1, \2. |
To use grep pattern matching to search for and replace text in a file:
First we prompt the user to select the file to open and store the reference to that file (as an alias) in the variable myFile.
Now we let AppleScript know that we want to send commands to BBEdit.
Then we have BBEdit open the file referred to by myFile.
This one simple line does something pretty incredible thanks to grep pattern matching. It finds every instance of the literal text "the" followed by a space and another word (which is defined in grep as one or more characters between a and z). Once it finds an instance, BBEdit replaces the characters with the literal text "the crazy".
Code w1.1. Using grep search and replace in BBEdit to match patterns and replace them.
Note: Lines wrapped with red arrows should be typed on a single
line.
Fig. w1.3 Our sample text file in BBEdit after the script has changed the word immediately following each "the" to "crazy."
For our next BBEdit trick, we'll create a script that will become a drag-and-drop application to batch process any number of text files in any number of nested folders (see Code w1.2). The heart of our routine will be the same replace command used in Code w1.1.
Keep in mind that once you've opened the file in BBEdit you can issue any number of replace commands to modify the open file before your script saves the changed file and moves on.
Once you've entered this script in the Script Editor, save it as an application on your Desktop, checking the Never Show Startup Screen option. This will make the script execute immediately when a user double-clicks its icon or drops files onto it. Then either drag and drop the Text Files folder we created earlier onto it or double-click it to be prompted to find a folder to process. Figure w1.4 shows what happens if you double-click the script application instead of dropping a folder onto it.
To start, we define an on run handler to deal with occasions when the user double-clicks the script application instead of dropping a folder onto it.
If the script was run by double-clicking, we prompt the user to select a folder to batch process and store the reference to that folder in the variable myFolder.
Then, we call the main function, batchProcess, passing to it the reference to the folder contained in myFolder.
If the user drops a folder onto the script application, the Finder will pass a reference to the folder to our script in the variable myFolder. Then, we call the main function as above, passing the reference to the folder.
Here, we begin our function, batchProcess, and tell AppleScript to store any value passed to it in the variable myCurrentFolder.
Next, we let AppleScript know that we want to talk to the Finder.
We ask the Finder to return a list of items contained in the folder referred to by myCurrentFolder and store it in myFolderContents.
Now we begin a repeat loop, placing one item from the list myFolderContents into the variable myFile for each loop until we reach the end of the list.
We ask the Finder for the type of item myFile in the folder referred to by myCurrentFolder. If it's a folder then our script will execute the next line.
If our function encounters another folder, it will call itself, passing a reference to the enclosed folder. In this way, our script processes all folders nested inside of the original.
If the item myFile in the folder isn't itself a folder, we begin talking to BBEdit.
First, we ask BBEdit to open the item myFile inside of the folder myCurrentFolder. We have to coerce the values to text to make sure AppleScript doesn't evaluate them as a list, which would generate an error.
Now BBEdit replaces our search string with the replace text using grep pattern matching and starting at the beginning of the document.
Finally, we have BBEdit save the changed file over itself and conclude our conversation, our if statement, our repeat loop, and our function.
Code w1.2. This elaborate script allows the user to either drag and drop or select folders to batch search and replace within BBEdit, saving the changes.
Note: Lines wrapped with red arrows should be typed on a single
line.
Fig. w1.4 When this script is run by double-clicking, the on run handler displays this dialog to allow the user to select a folder to batch process.
There are often times when you'd like to compare two files to see if they are different. BBEdit makes this very easy with its find differences statement.
Code w1.3 performs a comparison of two files specified by the user and reports whether they are the same or different. Figure w1.5 shows the result of a comparison of our two sample text files, 1 and 2.
This script can be run from the Script Editor.
We begin this script by prompting the user to select the first file for comparison and saving the reference to the file in the variable myFile1.
Then we prompt for the second file and save its reference in myFile2.
Here we ask BBEdit to compare the two files and return the result of the comparison as a Boolean (true or false) value in the variable areDifferent.
Next, we have BBEdit close the Find Differences windows it opened in the last command.
Finally, we evaluate the value of areDifferent and display one of two dialogs based on its value.
Tips
set myFile1 to (choose file with prompt "Select first file for comparison:")set myFile2 to (choose file with prompt "Select second file:")
tell application "BBEdit 4.5" set areDifferent to (find differences new myFile1 old myFile2) close every windowend tellif areDifferent then display dialog "These files are different."else display dialog "These files are the same."end if
Code w1.3. Performs a comparison of two files specified by the user and reports whether they are the same or different.
Note: Lines wrapped with red arrows should be typed on a single
line.
Fig. w1.5 The dialog displayed by Code w1.3 for nonmatching text files.
So now that we can slice, dice, and puree our text files with BBEdit and AppleScript, wouldn't it be nice to keep track of what's changed in a simple and clear manner? And what could be easier than labeling any changes in the Finder so that we can see what's happened at a glance?
Code w1.4 replaces any instances of "dog" that it finds in a text file with "cat", labeling the file in the Finder if any changes were made. Try running this script from the Script Editor and selecting one of our sample text files. Figure w1.6 shows the result.
To label changed files in the Finder:
Here we tell BBEdit to open the file referred to by myFile, which we prompted the user for at the beginning of the script.
Next, we test for a match for the search string ³dog² and store the Boolean result in the variable myFound. We need to use the find command first to find out if the string match exists. It returns a Boolean value to let us know if the string exists. The replace command doesn't return any such value.
We test myFound to see if it contains the value true.
If myFound is true, then we replace the literal text "dog" with "cat".
Then we close the window, sav
Finally, we tell the Finder to set the label of the file to indicate that it's been changed.
If the search string wasn't found in the file, we simply close its window in BBEdit.
Code w1.4. This script replaces any instances of "dog" in finds in a text file with "cat", labeling changed files in the Finder.
Note: Lines wrapped with red arrows should be typed on a single
line.
Fig. w1.6 A view of the Finder window showing the text file's icon with its label after our script has run.
Code w1.5 traverses every line of text in a file sequentially, searching for lines below the current line that match it. All matching lines are replaced with a null string, eliminating them. This script is useful for stripping duplicate entries from flat text file databases.
Figure w1.7 shows the active window in BBEdit as it appears while the script is running.
We begin by telling BBEdit to come to the front. Then we start looping through each line of the frontmost open window in BBEdit.
Next, we set myLine to the contents of the current line in our loop.
Then we tell BBEdit to go to the line just after the current line.
Now we have BBEdit search from the line below the current line to the end of the document without using grep pattern matching, replacing any duplicate lines it finds with null strings.
Code w1.5. This script traverses every line of text in a file sequentially, searching for lines below the current line that match it.
Note: Lines wrapped with red arrows should be typed on a single
line.
Fig. w1.7 The active window in BBEdit as it appears while the script is running.
Code w1.6 is a variation on our previous batch replace script (Code w1.2). It is a drag-and-drop application that can batch process any number of text files in any number of nested folders.
This script removes all tabs and multiple spaces in the files, saving disk space by eliminating the unneeded code indentation added by most visual editors.
Figure w1.8 displays the Get Info windows for a file before and after processing, showing the file size difference in bytes.
To start, we define an on run handler to deal with occasions when the user double-clicks the script application instead of dropping a folder onto it.
If the script was run by double-clicking, we prompt the user to select a folder to batch process and store the reference to that folder in the variable myFolder.
Then, we call the main function, batchProcess, passing to it the reference to the folder contained in myFolder.
If the user drops a folder onto the script application, the Finder will pass a reference to the folder to our script in the variable myFolder. Then, we call the main function as above, passing it the reference to the folder.
Here, we begin our function, batchProcess, and tell AppleScript to store any value passed to it in the variable myCurrentFolder.
Next, we let AppleScript know that we want to talk to the Finder.
We ask the Finder to return a list of items contained in the folder referred to by myCurrentFolder and store it in myFolderContents.
Now we begin a repeat loop, placing one item from the list myFolderContents into the variable myFile for each loop until we reach the end of the list.
We ask the Finder for the type of item myFile in the folder referred to by myCurrentFolder. If it's a folder, then our script will execute the next line.
If our function encounters another folder, it will call itself, passing a reference to the enclosed folder. In this way, our script processes all folders nested inside of the original.
If the item myFile in the folder isn't itself a folder, we begin talking to BBEdit.
First, we ask BBEdit to open the item myFile inside of the folder myCurrentFolder. We have to coerce the values to text to make sure AppleScript doesn't evaluate them as a list, which would generate an error.
Now BBEdit replaces all tabs with a null string and all multiple space characters with a single space, eliminating the file-bloating code indentation that many visual editors add to HTML files.
Finally, we have BBEdit save the changed file over itself and conclude our conversation, our if statement, our repeat loop, and our function.
Code w1.6. This script removes all tabs and multiple spaces in a file, eliminating the unneeded code indentation added by most visual editors.
Note: Lines wrapped with red arrows should be typed on a single
line.
Fig. w1.8 displays the Get Info windows for a file before and after processing, showing the file size difference in bytes.